home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 2
/
Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso
/
Aminet
/
util
/
gnu
/
oleo_src.lha
/
src
/
byte_compile.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-13
|
24KB
|
865 lines
/* Copyright (C) 1990 Free Software Foundation, Inc.
This file is part of Oleo, the GNU Spreadsheet.
Oleo is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
Oleo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "funcdef.h"
#include <stdio.h>
#define obstack_chunk_alloc ck_malloc
#define obstack_chunk_free free
#include "obstack.h"
#include "sysdef.h"
#include "global.h"
#include "node.h"
#include "eval.h"
/* should be struct var *, but we're cheating */
extern void add_var_ref EXT1(void *);
static void add_backpatch EXT2(unsigned, unsigned);
struct backpatch {
unsigned from,to;
};
static struct backpatch *patches;
static int patches_allocated;
static int patches_used;
static VOIDSTAR fn_stack;
static VOIDSTAR str_stack;
struct obstack tmp_mem;
VOIDSTAR tmp_mem_start;
extern double atan2 EXT2(double,double);
extern double hypot EXT2(double,double);
extern double floor EXT1(double);
extern double cos EXT1(double);
extern double to_int EXT1(double);
extern double dtr EXT1(double);
extern double rtd EXT1(double);
extern double exp EXT1(double);
extern double log10 EXT1(double);
extern double sin EXT1(double);
extern double sqrt EXT1(double);
extern double tan EXT1(double);
extern double acos EXT1(double);
extern double asin EXT1(double);
extern double atan EXT1(double);
extern double ceil EXT1(double);
#define V (void(*)())
/* These have to go in some file or other, so it is stuck in here (for now).
*/
struct function the_funs[] = {
{ 0, X_A0, "", 0, "<END>" },
{ 0, X_A0, "", 0, "<DUMMY1>" },
{ C_IF|R|INF(1), X_A1|X_J, "D", 0, "?" },
{ C_IF|R|INF(1), X_A1|X_JL, "D", 0, "?" },
{ C_IF, X_A1|X_J, "D", 0, "if" },
{ C_IF, X_A1|X_JL, "D", 0, "if" },
{ C_ANDOR, X_A1|X_J, "D", 0, "and" },
/* { C_ANDOR|L|INF(3), X_A1, "DD", 0, "&" }, */
{ C_ANDOR, X_A1|X_JL, "D", 0, "and" },
/* { C_ANDOR|L|INF(3), X_A1, "DD", 0, "&" }, */
{ C_ANDOR, X_A1|X_J, "D", 0, "or" },
/* { C_ANDOR|L|INF(2), X_A1, "DD", 0, "|" }, */
{ C_ANDOR, X_A1|X_JL, "D", 0, "or" },
/* { C_ANDOR|L|INF(2), X_A1, "DD", 0, "|" }, */
{ C_STR, X_A0|X_J, "", 0, "\"%s\"" },
{ C_STR, X_A0|X_JL, "", 0, "\"%s\"" },
#ifdef A0_REFS
{ C_CELL, X_A0, "", 0, "$%s$%u" },
{ C_CELL, X_A0, "", 0, "$%s%u" },
{ C_CELL, X_A0, "", 0, "%s$%u" },
{ C_CELL, X_A0, "", 0, "%s%u" },
{ C_RANGE, X_A0, "", 0, "$%s$%u:$%s$%u" },
{ C_RANGE, X_A0, "", 0, "$%s%u:$%s$%u" },
{ C_RANGE, X_A0, "", 0, "$%s$%u:$%s%u" },
{ C_RANGE, X_A0, "", 0, "$%s%u:$%s%u" },
{ C_RANGE, X_A0, "", 0, "%s$%u:$%s$%u" },
{ C_RANGE, X_A0, "", 0, "%s%u:$%s$%u" },
{ C_RANGE, X_A0, "", 0, "%s$%u:$%s%u" },
{ C_RANGE, X_A0, "", 0, "%s%u:$%s%u" },
{ C_RANGE, X_A0, "", 0, "$%s$%u:%s$%u" },
{ C_RANGE, X_A0, "", 0, "$%s%u:%s$%u" },
{ C_RANGE, X_A0, "", 0, "$%s$%u:%s%u" },
{ C_RANGE, X_A0, "", 0, "$%s%u:%s%u" },
{ C_RANGE, X_A0, "", 0, "%s$%u:%s$%u" },
{ C_RANGE, X_A0, "", 0, "%s%u:%s$%u" },
{ C_RANGE, X_A0, "", 0, "%s$%u:%s%u" },
{ C_RANGE, X_A0, "", 0, "%s%u:%s%u" },
#else
{ C_CELL, X_A0, "", 0, "r%uc%u" },
{ C_CELL, X_A0, "", 0, "r[%+d]c%u" },
{ C_CELL, X_A0, "", 0, "r%uc[%+d]" },
{ C_CELL, X_A0, "", 0, "r[%+d]c[%+d]" },
{ C_RANGE, X_A0, "", 0, "r%u:%uc%u:%u" },
{ C_RANGE, X_A0, "", 0, "r[%+d]:%uc%u:%u" },
{ C_RANGE, X_A0, "", 0, "r%u:[%+d]c%u:%u" },
{ C_RANGE, X_A0, "", 0, "r[%+d]:[%+d]c%u:%u" },
{ C_RANGE, X_A0, "", 0, "r%u:%uc[%+d]:%u" },
{ C_RANGE, X_A0, "", 0, "r[%+d]:%uc[%+d]:%u" },
{ C_RANGE, X_A0, "", 0, "r%u:[%+d]c[%+d]:%u" },
{ C_RANGE, X_A0, "", 0, "r[%+d]:[%+d]c[%+d]:%u" },
{ C_RANGE, X_A0, "", 0, "r%u:%uc%u:[%+d]" },
{ C_RANGE, X_A0, "", 0, "r[%+d]:%uc%u:[%+d]" },
{ C_RANGE, X_A0, "", 0, "r%u:[%+d]c%u:[%+d]" },
{ C_RANGE, X_A0, "", 0, "r[%+d]:[%+d]c%u:[%+d]" },
{ C_RANGE, X_A0, "", 0, "r%u:%uc[%+d]:[%+d]" },
{ C_RANGE, X_A0, "", 0, "r[%+d]:%uc[%+d]:[%+d]" },
{ C_RANGE, X_A0, "", 0, "r%u:[%+d]c[%+d]:[%+d]" },
{ C_RANGE, X_A0, "", 0, "r[%+d]:[%+d]c[%+d]:[%+d]" },
#endif
{ C_CONST, X_A0, "", 0, tname },
{ C_CONST, X_A0, "", 0, fname },
{ C_CONST, X_A0, "", 0, iname },
{ C_CONST, X_A0, "", 0, mname },
{ C_CONST, X_A0, "", 0, nname },
{ C_ERR, X_A0|X_J, "", 0, "%s" },
{ C_FLT, X_A0, "", 0, "%.15g" },
{ C_INT, X_A0, "", 0, "%ld" },
{ C_VAR, X_A0, "", 0, "%s" },
{ C_UNA, X_A1, "F", 0, "-" },
{ C_UNA, X_A1, "B", 0, "!" },
{ C_INF|L|INF(6), X_A2, "NN", 0, "-" },
{ C_INF|L|INF(7), X_A2, "NN", 0, "/" },
{ C_INF|L|INF(7), X_A2, "NN", 0, "%" },
{ C_INF|L|INF(7), X_A2, "NN", 0, "*" },
{ C_INF|L|INF(6), X_A2, "NN", 0, "+" },
{ C_INF|L|INF(2), X_A2, "SS", 0, "&" },
{ C_INF|N|INF(4), X_A2, "AA", 0, "=" },
{ C_INF|N|INF(5), X_A2, "AA", 0, ">=" },
{ C_INF|N|INF(5), X_A2, "AA", 0, ">" },
{ C_INF|N|INF(5), X_A2, "AA", 0, "<" },
{ C_INF|N|INF(5), X_A2, "AA", 0, "<=" },
{ C_INF|N|INF(4), X_A2, "AA", 0, "!=" },
{ C_INF|R|INF(8), X_A2, "FF", V pow, "^" },
{ C_FN0, X_A0, "", 0, "pi" },
{ C_FN0X, X_A0, "", 0, "row" },
{ C_FN0X, X_A0, "", 0, "col" },
{ C_FN0|C_T, X_A0, "", 0, "now" },
{ C_FN1, X_A1, "F", V fabs, "abs" },
{ C_FN1, X_A1, "F", V acos, "acos" },
{ C_FN1, X_A1, "F", V asin, "asin" },
{ C_FN1, X_A1, "F", V atan, "atan" },
{ C_FN1, X_A1, "F", V ceil, "ceil" },
{ C_FN1, X_A1, "F", V to_int, "int" },
{ C_FN1, X_A1, "F", V floor, "floor" },
{ C_FN1, X_A1, "F", V cos, "cos" },
{ C_FN1, X_A1, "F", V dtr, "dtr" },
{ C_FN1, X_A1, "F", V exp, "exp" },
{ C_FN1, X_A1, "F", V log, "log" },
{ C_FN1, X_A1, "F", V log10, "log10" },
{ C_FN1, X_A1, "F", V rtd, "rtd" },
{ C_FN1, X_A1, "F", V sin, "sin" },
{ C_FN1, X_A1, "F", V sqrt, "sqrt" },
{ C_FN1, X_A1, "F", V tan, "tan" },
{ C_FN1, X_A1, "I", 0, "ctime" },
{ C_FN1, X_A1, "A", 0, "negate" },
{ C_FN1, X_A1, "A", 0, "not" },
{ C_FN1, X_A1, "A", 0, "iserr" },
{ C_FN1, X_A1, "A", 0, "isnum" },
{ C_FN1|C_T, X_A1, "I", 0, "rnd" },
{ C_FN1, X_A1, "R", 0, "rows" },
{ C_FN1, X_A1, "R", 0, "cols" },
{ C_FN2, X_A2, "FF", V atan2, "atan2" },
{ C_FN2, X_A2, "FF", V hypot, "hypot" },
{ C_FN2, X_A2, "FI", 0, "fixed" },
{ C_FN2, X_A2, "AA", 0, "iferr" },
{ C_FN2, X_A2, "RI", 0, "index" },
{ C_FN3, X_A3, "RII", 0, "index" },
{ C_FNN, X_AN, "IAAA", 0, "oneof" },
{ C_FNN, X_AN, "SIIA", 0, "file" },
{ C_FNN, X_AN, "EEEE", 0, "sum" },
{ C_FNN, X_AN, "EEEE", 0, "prod" },
{ C_FNN, X_AN, "EEEE", 0, "avg" },
{ C_FNN, X_AN, "EEEE", 0, "std" },
{ C_FNN, X_AN, "EEEE", 0, "max" },
{ C_FNN, X_AN, "EEEE", 0, "min" },
{ C_FNN, X_AN, "EEEE", 0, "count" },
{ C_FNN, X_AN, "EEEE", 0, "var" },
};
#ifdef USE_DLD
int n_usr_funs;
struct function **usr_funs;
int *usr_n_funs;
#else
int n_usr_funs = 3;
extern struct function busi_funs[];
extern struct function string_funs[];
extern struct function cells_funs[];
static struct function *__usr_funs[] = {
busi_funs,
string_funs,
cells_funs,
};
static int __usr_n_funs[] = {
18, 11, 10
};
struct function **usr_funs = __usr_funs;
int *usr_n_funs = __usr_n_funs;
#endif
/* ... A whole huge empty space, then ... */
struct function skip_funs[] = {
{ C_SKIP, X_A0|X_J, "", 0, "<Skip %u>" },
{ C_SKIP, X_A0|X_JL, "", 0, "<SkipL %u>" },
};
/* The memory allocated here is used for several things, but byte_compile
is a small file, so it might as well be here */
void
init_mem FUN0()
{
int n;
extern VOIDSTAR hash_new();
parse_hash=hash_new();
hash_insert(parse_hash,the_funs[F_IF].fn_str,&the_funs[F_IF]);
hash_insert(parse_hash,the_funs[AND].fn_str,&the_funs[AND]);
hash_insert(parse_hash,the_funs[OR].fn_str,&the_funs[OR]);
for(n=F_PI;n<USR1;n++)
hash_insert(parse_hash,the_funs[n].fn_str,&the_funs[n]);
#ifndef USE_DLD
for(n=0;n<n_usr_funs;n++) {
int nn;
for(nn=0;usr_funs[n][nn].fn_str;nn++)
hash_insert(parse_hash,usr_funs[n][nn].fn_str,&usr_funs[n][nn]);
#ifdef TEST
if(usr_n_funs[n]!=nn) {
fprintf(stderr,"Usr_n_funs[%d]%d!=%d",n,usr_n_funs[n],nn);
usr_n_funs[n]=nn;
}
#endif
}
#endif
fn_stack=init_stack();
str_stack=init_stack();
obstack_begin(&tmp_mem,400);
tmp_mem_start=obstack_alloc(&tmp_mem,0);
}
#ifdef USE_DLD
void
add_usr_funs FUN1(struct function *,new_funs)
{
int n;
n_usr_funs++;
usr_funs=usr_funs ? ck_realloc(usr_funs,n_usr_funs*sizeof(struct function *)) : ck_malloc(sizeof(struct function *));
usr_n_funs = usr_n_funs ? ck_realloc(usr_n_funs,n_usr_funs*sizeof(int)) : ck_malloc(sizeof(int));
usr_funs[n_usr_funs-1]=new_funs;
for(n=0;new_funs[n].fn_str;n++)
hash_insert(parse_hash,new_funs[n].fn_str,&new_funs[n]);
usr_n_funs[n_usr_funs-1]=n;
}
#endif
/* Stash away a backpatch for future editing. */
static void
add_backpatch FUN2(unsigned, from,unsigned, to)
{
if(!patches) {
patches_allocated=5;
patches=(struct backpatch *)ck_malloc(patches_allocated*sizeof(struct backpatch));
patches_used=0;
}
if(patches_allocated==patches_used) {
patches_allocated*=2;
patches=(struct backpatch *)ck_realloc(patches,patches_allocated*sizeof(struct backpatch));
}
patches[patches_used].from=from;
patches[patches_used].to=to;
patches_used++;
}
static int
cmp_patch FUN2(int,n1, int,n2)
{
int ret;
ret=(patches[n1].from == patches[n2].from) ? patches[n1].to-patches[n2].to : patches[n1].from - patches[n2].from;
return ret;
}
static void
swp_patch FUN2(int,n1, int,n2)
{
struct backpatch tmp;
tmp=patches[n1];
patches[n1]=patches[n2];
patches[n2]=tmp;
}
static void
rot_patch FUN2(int,n1, int,n2)
{
struct backpatch tmp;
tmp=patches[n2];
while(n2>n1) {
patches[n2]=patches[n2-1];
--n2;
}
patches[n2]=tmp;
}
/* This takes an ascii string and returns a pointer to the byte-compiled
result. It calls yyparse() to do the actual parsing. This is complicated
only because yyparse returns a parse tree which needs to be turned into
postfix compiled bytes. This is further complicated by the presence of
forward branches in the byte-compiled code. That's what the backpatch
stuff is for.
It'd be nice if oneof() could compile into
arg1
ONEOF n_possibilities
JUMP poss1
JUMP poss2
JUMP poss3
...
JUMP error
{poss 1}
JUMP end
{poss 2}
JUMP end
...
end: {rest of expression}
instead of the simplistic (and slow-to-execute) version currently used
It'd also be nice if byte-compiled expressions could have *BIG*
subexpressions, instead of silently failing as they do now. Error checking
and a way to encode longer branches would be a *good* idea.
*/
unsigned char *
parse_and_compile FUN1(char *,string)
{
struct node *new_node;
struct node *node;
struct function *f;
unsigned char *ret;
int n;
unsigned buf_siz;
int need_relax;
int byte;
extern int yyparse EXT0();
extern char *instr;
extern int parse_error;
extern struct node *parse_return;
instr=string;
parse_error=0;
patches_used=0;
if(yyparse() || parse_error) {
ret=ck_malloc(strlen(string)+5);
ret[0]=CONST_ERR;
ret[1]=2;
ret[2]=parse_error;
ret[3]=ENDCOMP;
strcpy((char *)&ret[4],string);
(void)obstack_free(&tmp_mem,tmp_mem_start);
return ret;
}
node=parse_return;
if(!node)
return 0;
loop:
if(node->comp_value<USR1) {
f= &the_funs[node->comp_value];
byte=node->comp_value;
} else if(node->comp_value<SKIP) {
n=node->sub_value;
f= &usr_funs[node->comp_value-USR1][n];
/* Wait until this has no subrs left. . . */
if(!node->n_x.v_subs[0] && !node->n_x.v_subs[1])
(void)obstack_1grow(&tmp_mem,(int)node->comp_value);
/* Cheat */
byte=node->sub_value;
} else {
f= &skip_funs[node->comp_value-SKIP];
byte=node->comp_value;
}
#ifdef TEST
if(!f)
panic("f is zero in byte_compile!");
#endif
switch(GET_COMP(f->fn_comptype)) {
case C_IF:
/* if compiles to
test-code IF amt-to-skip-on-false true-code SKIP
amt-to-skip-on-true false-code */
if(node->n_x.v_subs[0]) {
if(node->n_x.v_subs[0]->n_x.v_subs[0]) {
/* Put out the test-code */
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[0]->n_x.v_subs[0];
node->n_x.v_subs[0]->n_x.v_subs[0]=0;
node=new_node;
goto loop;
}
/* Put out IF, null-byte to backpatch */
(void)obstack_1grow(&tmp_mem,byte);
node->add_byte=obstack_object_size(&tmp_mem);
(void)obstack_1grow(&tmp_mem,0);
/* put out true-code */
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[0]->n_x.v_subs[1];
node->n_x.v_subs[0]=0;
node=new_node;
goto loop;
}
if(node->n_x.v_subs[1]) {
(void)obstack_1grow(&tmp_mem,SKIP);
(void)obstack_1grow(&tmp_mem,0);
add_backpatch(node->add_byte,obstack_object_size(&tmp_mem));
node->add_byte=obstack_object_size(&tmp_mem)-1;
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[1];
node->n_x.v_subs[1]=0;
node=new_node;
goto loop;
}
add_backpatch(node->add_byte,obstack_object_size(&tmp_mem));
break;
case C_ANDOR:
if(node->n_x.v_subs[0]) {
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[0];
node->n_x.v_subs[0]=0;
node=new_node;
goto loop;
}
if(node->n_x.v_subs[1]) {
(void)obstack_1grow(&tmp_mem,byte);
node->add_byte=obstack_object_size(&tmp_mem);
(void)obstack_1grow(&tmp_mem,0); /* for backpatching */
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[1];
node->n_x.v_subs[1]=0;
node=new_node;
goto loop;
}
add_backpatch(node->add_byte,obstack_object_size(&tmp_mem));
break;
case C_ERR:
(void)obstack_1grow(&tmp_mem,byte);
node->add_byte=obstack_object_size(&tmp_mem);
(void)obstack_1grow(&tmp_mem,0);
(void)obstack_1grow(&tmp_mem,node->n_x.v_int);
node->n_x.v_string=ename[node->n_x.v_int];
push_stack(str_stack,node);
break;
case C_FLT:
(void)obstack_1grow(&tmp_mem,byte);
(void)obstack_grow(&tmp_mem,&(node->n_x.v_float),sizeof(double));
break;
case C_INT:
(void)obstack_1grow(&tmp_mem,byte);
(void)obstack_grow(&tmp_mem,&(node->n_x.v_int),sizeof(long));
break;
case C_STR:
(void)obstack_1grow(&tmp_mem,byte);
node->add_byte=obstack_object_size(&tmp_mem);
(void)obstack_1grow(&tmp_mem,0);
push_stack(str_stack,node);
break;
case C_VAR:
add_ref_to(obstack_object_size(&tmp_mem));
add_var_ref(node->n_x.v_var);
(void)obstack_1grow(&tmp_mem,byte);
(void)obstack_grow(&tmp_mem,&(node->n_x.v_var),sizeof(struct var *));
break;
case C_CELL:
add_ref_to(obstack_object_size(&tmp_mem));
add_ref(node->n_x.v_rng.lr,node->n_x.v_rng.lc);
(void)obstack_1grow(&tmp_mem,byte);
#if BITS_PER_CELLREF==16
(void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lr>>8);
(void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lr);
(void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lc>>8);
(void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lc);
#else
#if BITS_PER_CELLREF==8
(void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lr);
(void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lc);
#else
Insert appropriate code here
#endif
#endif
break;
case C_RANGE:
add_ref_to(obstack_object_size(&tmp_mem));
add_range_ref(&(node->n_x.v_rng));
(void)obstack_1grow(&tmp_mem,byte);
(void)obstack_grow(&tmp_mem,&(node->n_x.v_rng),sizeof(struct rng));
break;
case C_FN0:
case C_CONST:
if(f->fn_comptype&C_T)
add_timer_ref(obstack_object_size(&tmp_mem));
(void)obstack_1grow(&tmp_mem,byte);
break;
case C_FN0X:
add_ref_to(obstack_object_size(&tmp_mem));
(void)obstack_1grow(&tmp_mem,byte);
break;
case C_FN1:
case C_UNA:
if(node->n_x.v_subs[0]) {
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[0];
node->n_x.v_subs[0]=0;
node=new_node;
goto loop;
}
if(f->fn_comptype&C_T)
add_timer_ref(obstack_object_size(&tmp_mem));
(void)obstack_1grow(&tmp_mem,byte);
break;
case C_FN2:
case C_INF:
if(node->n_x.v_subs[0]) {
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[0];
node->n_x.v_subs[0]=0;
node=new_node;
goto loop;
}
if(node->n_x.v_subs[1]) {
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[1];
node->n_x.v_subs[1]=0;
node=new_node;
goto loop;
}
(void)obstack_1grow(&tmp_mem,byte);
break;
case C_FN3:
if(node->n_x.v_subs[0]) {
if(node->n_x.v_subs[0]->n_x.v_subs[0]) {
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[0]->n_x.v_subs[0];
node->n_x.v_subs[0]->n_x.v_subs[0]=0;
node=new_node;
goto loop;
}
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[0]->n_x.v_subs[1];
node->n_x.v_subs[0]=0;
node=new_node;
goto loop;
}
if(node->n_x.v_subs[1]) {
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[1];
node->n_x.v_subs[1]=0;
node=new_node;
goto loop;
}
if(f->fn_comptype&C_T)
add_timer_ref(obstack_object_size(&tmp_mem));
(void)obstack_1grow(&tmp_mem,byte);
break;
case C_FN4:
if(node->n_x.v_subs[0]) {
if(node->n_x.v_subs[0]->n_x.v_subs[0]) {
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[0]->n_x.v_subs[0];
node->n_x.v_subs[0]->n_x.v_subs[0]=0;
node=new_node;
goto loop;
}
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[0]->n_x.v_subs[1];
node->n_x.v_subs[0]=0;
node=new_node;
goto loop;
}
if(node->n_x.v_subs[1]) {
if(node->n_x.v_subs[1]->n_x.v_subs[0]) {
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[1]->n_x.v_subs[0];
node->n_x.v_subs[1]->n_x.v_subs[0]=0;
node=new_node;
goto loop;
}
push_stack(fn_stack,node);
new_node=node->n_x.v_subs[1]->n_x.v_subs[1];
node->n_x.v_subs[1]=0;
node=new_node;
goto loop;
}
if(f->fn_comptype&C_T)
add_timer_ref(obstack_object_size(&tmp_mem));
(void)obstack_1grow(&tmp_mem,byte);
break;
case C_FNN:
if(node->n_x.v_subs[1]) {
if(node->add_byte==0)
for(new_node=node;new_node->n_x.v_subs[1];new_node=new_node->n_x.v_subs[1])
node->add_byte++;
for(new_node=node;new_node->n_x.v_subs[1]->n_x.v_subs[1];new_node=new_node->n_x.v_subs[1])
;
push_stack(fn_stack,node);
node=new_node->n_x.v_subs[1]->n_x.v_subs[0];
new_node->n_x.v_subs[1]=0;
goto loop;
}
(void)obstack_1grow(&tmp_mem,byte);
(void)obstack_1grow(&tmp_mem,node->add_byte);
break;
default:
panic("Bad comptype %d",f->fn_comptype);
}
node=(struct node *)pop_stack(fn_stack);
if(node)
goto loop;
(void)obstack_1grow(&tmp_mem,0);
while(node=pop_stack(str_stack)) {
add_backpatch(node->add_byte,obstack_object_size(&tmp_mem));
(void)obstack_grow(&tmp_mem,node->n_x.v_string,strlen(node->n_x.v_string)+1);
}
buf_siz=obstack_object_size(&tmp_mem);
ret=(unsigned char *)ck_malloc(buf_siz);
bcopy(obstack_finish(&tmp_mem),ret,buf_siz);
need_relax=0;
for(n=0;n<patches_used;n++) {
long offset;
offset=(patches[n].to-patches[n].from)-1;
if(offset<0 || offset>255)
need_relax++;
else
ret[patches[n].from]=offset;
}
if(need_relax) {
int n_lo;
long offset;
int start;
extern void sort();
/* ... Sort the patches list ... */
sort(patches_used,cmp_patch,swp_patch,rot_patch);
while(need_relax) {
ret=ck_realloc(ret,buf_siz+need_relax);
for(n_lo=0;n_lo<patches_used;n_lo++) {
offset=(patches[n_lo].to-patches[n_lo].from)-1;
if(offset<0 || offset>255-need_relax)
break;
}
/* n_lo points to the first jump that may need to be relaxed */
for(n=n_lo;n<patches_used;n++) {
offset=(patches[n].to-patches[n].from)-1;
if(offset<0 || offset>255) {
int nn;
start=patches[n].from;
ret[start-1]++;/* Translate insn to LONG */
ret[start ]=offset;
bcopy(&ret[start+1],&ret[start+2],buf_siz-start);
ret[start+1]=offset>>8;
need_relax--;
buf_siz++;
for(nn=0;nn<patches_used;nn++) {
if(patches[nn].from>start)
patches[nn].from++;
if(patches[nn].to>start)
patches[nn].to++;
if(patches[nn].from<start && patches[nn].to>start && ret[patches[nn].from]++==255) {
if(ret[patches[nn].from-1]&01)
ret[patches[nn].from+1]++;
else
need_relax++;
}
}
}
}
}
}
(void)obstack_free(&tmp_mem,tmp_mem_start);
patches_used=0;
return ret;
}
/* Back when strings stored a char*, they needed to be freed when a
byte-compiled expression was freed. Now that they're appended to the end,
they don't need to be specially freed anymore.
*/
void
byte_free FUN1(unsigned char *,form)
{
/* no longer needed
unsigned char *f;
for(f=form;*f;f++) {
switch(*f) {
case IF:
case F_IF:
case SKIP:
case AND:
case OR:
case CONST_STR:
f++;
break;
case CONST_INT:
f+=sizeof(long);
break;
case CONST_FLT:
f+=sizeof(double);
break;
case VAR:
f+=sizeof(struct var *);
break;
case R_CELL:
case R_CELL|ROWREL:
case R_CELL|COLREL:
case R_CELL|ROWREL|COLREL:
f+=EXP_ADD;
break;
case RANGE:
case RANGE|LRREL:
case RANGE|LRREL|LCREL:
case RANGE|LRREL|LCREL|HCREL:
case RANGE|LRREL|HCREL:
case RANGE|LRREL|HRREL:
case RANGE|LRREL|HRREL|LCREL:
case RANGE|LRREL|HRREL|LCREL|HCREL:
case RANGE|LRREL|HRREL|HCREL:
case RANGE|HRREL:
case RANGE|HRREL|LCREL:
case RANGE|HRREL|LCREL|HCREL:
case RANGE|HRREL|HCREL:
case RANGE|LCREL:
case RANGE|LCREL|HCREL:
case RANGE|HCREL:
f+=EXP_ADD_RNG;
break;
case F_PRINTF:
case F_CONCAT:
case F_ONEOF:
case F_STRSTR:
case F_EDIT:
case AREA_SUM:
case AREA_PROD:
case AREA_AVG:
case AREA_STD:
case AREA_MAX:
case AREA_MIN:
case AREA_CNT:
case AREA_VAR:
f++;
break;
default:
break;
}
} */
free(form);
}
/* This tries to tell if a byte-compiled expression is a constant. If it
is a constant, we can free it, and never try to recompute its value.
This returns non-zero if the expression is constant.*/
int
is_constant FUN1(unsigned char *,bytes)
{
/* It's constant, but it's already been dealt with.
Pretend it isn't. */
if(!bytes)
return 0;
switch(bytes[0]) {
case CONST_ERR:
return (bytes[3]==0 && !strcmp((char *)bytes+4,ename[bytes[2]]));
case CONST_INT:
return bytes[sizeof(long)+1]==ENDCOMP;
case CONST_FLT:
return bytes[sizeof(double)+1]==ENDCOMP;
case CONST_STR:
return bytes[2]==ENDCOMP;
case F_TRUE:
case F_FALSE:
case CONST_INF:
case CONST_NINF:
case CONST_NAN:
return bytes[1]==ENDCOMP;
default:
return 0;
}
}